/**********************************
tcp_ser.c: the source file of the server in tcp transmission 
***********************************/

#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <math.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/time.h>

#include <pthread.h>

# include <vector>
# include <string>

using namespace std;

#define MYTCP_PORT 31038
#define BUFSIZE 60000
#define PACKLEN 508
#define HEADLEN 8

#define BACKLOG 10

pthread_t worker;

int sockfd, con_fd, ret;
struct sockaddr_in my_addr;
struct sockaddr_in their_addr;
socklen_t sin_size;

pid_t pid;

vector<string> url;

bool getByte(int socket, char &x)
{
	int n;

	if ((n = recv(socket, &x, 1, 0))==-1)
	{
		printf("error when receiving\n");
		return false;
	}

	return true;
}

bool getString(int socket, string &s)
{
	char newByte = 1;
	s = "";

	while (newByte)
	{
		if (!getByte(socket, newByte))
		{
			printf("error when receiving\n");
			return false;
		}

		s += newByte;
	}

	return true;
}

void *crawl(void * param)
{
	// while (1)
	// {
	// 	for (int i = 0; i < hardcodeURL.size(); i ++)
	// 	{
	// 		printf("before send\n");
	// 		sendString(hardcodeURL[i]);
	// 		printf("%s sent!\n", hardcodeURL[i].c_str());
	// 		sleep(1);
	// 	}
	// }
	send(con_fd, "www.stackoverflow.com", 22, 0);
	send(con_fd, "1234.5", 7, 0);
	send(con_fd, "www.sina.com", 13, 0);
	send(con_fd, "1234.6", 7, 0);
	send(con_fd, "www.nus.edu.sg", 15, 0);
	send(con_fd, "1234.7", 7, 0);
	send(con_fd, "www.comp.nus.edu.sg", 20, 0);
	send(con_fd, "1234.8", 7, 0);
	send(con_fd, "cppreference.com", 17, 0);
	send(con_fd, "1234.9", 7, 0);

	pthread_exit(NULL);
}

void str_ser(int sockfd)
{
	char opcode;
	char totalURL;
	char newByte;
	
	printf("receiving data!\n");

	if (getByte(sockfd, opcode) && opcode != 2)
	{
		printf("Opcode = %d\n", opcode);
		if (opcode == 0 && getByte(sockfd, totalURL))
		{
			pthread_create(&worker, NULL, crawl, NULL);

			printf("Total URL to receive = %d\n", totalURL);
			while(totalURL --)
			{
				string s;
				getString(sockfd, s);

				url.push_back(s);
			}
			
			pthread_join(worker, NULL);
			printf("Receving Complete.\n");

			for (int i = 0; i < (int)url.size(); i ++)
			{
				printf("%s\n", url[i].c_str());
			}
		}
	}

	pthread_cancel(worker);
}

int main()
{
//	char *buf;

//------------------- Bind Current Application to a Socket ------------------//
	sockfd = socket(AF_INET, SOCK_STREAM, 0);          //create socket
	if (sockfd <0)
	{
		printf("error in socket!");
		exit(1);
	}
	
	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons(MYTCP_PORT);
	my_addr.sin_addr.s_addr = htonl(INADDR_ANY);//inet_addr("172.0.0.1");
	bzero(&(my_addr.sin_zero), 8);
	ret = bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr));                //bind socket
	if (ret <0)
	{
		printf("error in binding");
		exit(1);
	}
	
	ret = listen(sockfd, BACKLOG);                              //listen
	if (ret <0) {
		printf("error in listening");
		exit(1);
	}

//--------------------------------- Start Serving ------------------------------------------//
	while (1)
	{
		printf("Waiting for URLs\n");
		sin_size = sizeof (struct sockaddr_in);
		con_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);            //accept the packet
		if (con_fd <0)
		{
			printf("error in accept\n");
			exit(1);
		}

		if ((pid = fork())==0)                                         // creat acception process
		{
			close(sockfd);
			str_ser(con_fd);                                          //receive packet and response
			close(con_fd);
			printf("Exiting\n");
			exit(0);
		}
		else close(con_fd);                                         //parent process
	}
	close(sockfd);
	exit(0);
}